module Main where
--import qualified Data.Binary.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BLC
import Data.Binary.Get
import System.IO
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as VM
import Control.Monad.Primitive



list_union::(Eq a)=>[a]->[a]->[a]
list_union [] x2=x2
list_union (x:xs) x2=if elem x x2
    then list_union xs x2
    else
        list_union xs (x:x2) 
        
list_intersection::(Eq a)=>[a]->[a]->[a]
list_intersection [] x1=[]
list_intersection x1 []=[]
list_intersection x1 x2=[i|i<- x1,elem i x2]


 
list_exchange:: [a]->Int->Int->[a]
list_exchange [] _ _=[]
list_exchange (x:[]) _ _ =[x]
list_exchange ys i j=[ys!!(\x->if x==j then i else if x==i then j else x) k|k<-[0..(length ys-1)]] 

list_remove::[a]->[(Int,Int)]->[a]
list_remove l [] =l
list_remove l ltu=[l!!i|i<-[0..length l -1],not $ elem i $ foldl (++) [] [[fst j.. snd j]|j<-ltu] ]

-- list_remove::[a]->[(Int,Int)]->[a]
-- list_remove l [] =l
-- list_remove l ltu=[l!!i|i<-[0..length l -1],not $ elem i $ foldl (++) [] [[fst j.. snd j]|j<-ltu] ]



list_replace:: [a]->Int->[a]->[a]
list_replace [] _ _ =[]
list_replace l index re=
    if len2 > len1 || index <0 ||index >=len1 ||index + len2-1 >=len1 then
        l
    else 
        [if elem i [index..(index+len2-1)] then re !! (i-index) else l !!i |i<-[0..len1-1]]
    where 
        len1=length l
        len2=length re 

list_split_on::Eq a=>[a]->a->[[a]]
---list_split_on l []=[l]
list_split_on l m = [[l!!j | j<- [li!!i+1 ..li!!(i+1)-1 ]] | i<-[0.. length li -2]]
    where 
        li=[-1]++[i | i<- [0..length l -1],l!!i == m]++[length l]


str_get_words_index::String->String->(Int,Int)
str_get_words_index str []=(-1,-1)
str_get_words_index str sstr=my_recur li str sstr
    where
        li=[-1]++[ i |i<-[0..length str -1],elem (str!!i) [' ','\n'] ]++[length str]
        my_recur::[Int]->String->String->(Int,Int)
        my_recur (l:l1) s ss =
            if length l1 <=0 then
                (-1,1)
            else if head l1-1<l || [s!! i | i<-[l+1..head l1-1]] /= ss then
                my_recur l1 s ss
            else
                (l+1,l+length ss)

bhGetLine::Handle->IO String
bhGetLine h=my_recur h ""
    where 
        my_recur::Handle->String->IO String
        my_recur h s= do
            s1<-BL.hGet h 1
            s2<- return $ BLC.unpack s1
            if s2 == "\n" then 
                return $ s++s2
            else
                my_recur h (s++s2)

----test_vec::VM.MVector (PrimState IO) Float-> IO (VM.MVector (PrimState IO) Float)



test :: IO()
test = do
    let 
        pcd_get_header:: Handle->IO String
        pcd_get_header h=my_recur h " " 11
            where 
                my_recur::Handle->String->Int ->IO String
                my_recur _ s 0= return s
                my_recur h s n= do
                    s1<-bhGetLine h
                    my_recur h (s++s1) (n-1)
        pcd_get_header_info::String->(Int,Int)
        pcd_get_header_info s=(a,b)
            where
                li=[str_get_words_index s i| i<-["SIZE","TYPE","COUNT","WIDTH","POINTS","DATA"]]
                s1=[s !!i | i<-[snd (li!!0)+7..fst (li!!1)-1]]
                s2=[s !!i | i<-[snd (li!!2)+7..fst (li!!3)-1]]
                s3=[s !!i | i<-[snd (li!!4)+1..fst (li!!5)-1]]
                b=read s3::Int
                s11=fmap read $ words s1:: [Int]
                s22=fmap read $ words s2::[Int] 
                a=sum $ zipWith (*) s11 s22

        pcd_alter_header::String->String
        pcd_alter_header s=re
            where
                li=[str_get_words_index s i| i<-["FIELDS","SIZE","TYPE","COUNT","WIDTH","DATA"]]
                li1=[snd (li!!0)+7..fst (li!!1)-2]++[snd (li!!1)+7..fst (li!!2)-2]++[snd (li!!2)+7..fst (li!!3)-2]++[snd (li!!3)+7..fst (li!!4)-2]++[snd (li!!5)+1..length s-1]
                re=[s!!i | i<-[0..length s -1],not $ elem i li1] ++ " ascii\n" 
        
        pcd_fill_vector::Handle->(Int,Int)->VM.MVector (PrimState IO) Float->IO (VM.MVector (PrimState IO ) Float)
        pcd_fill_vector h (sum,tsum) vec=my_recur h (sum,tsum) 0 vec
            where
                my_recur::Handle->(Int,Int)->Int->VM.MVector (PrimState IO) Float-> IO (VM.MVector (PrimState IO) Float)
                my_recur h1 (sum1,tsum1) n vec1 = 
                    if n==tsum1 then
                        return vec1
                    else do
                        s<-BL.hGet h1 4
                        VM.write  vec1 (n*3+0) $ runGet getFloatle s
                        s<-BL.hGet h1 4
                        VM.write  vec1 (n*3+1) $ runGet getFloatle s
                        s<-BL.hGet h1 4
                        VM.write  vec1 (n*3+2) $ runGet getFloatle s
                        s<-BL.hGet h1 sum1
                        my_recur h1 (sum1,tsum1) (n+1) vec1
        pcd_write_file::V.Vector Float->Handle->Int->IO()
        pcd_write_file vec h sum=my_recur vec h sum 0
            where
                my_recur::V.Vector Float->Handle->Int->Int->IO()
                my_recur vec1 h1 sum1 n=
                    if n>=sum1 then
                        return ()
                    else do
                        hPutStr h1 $ (show $vec1 V.! (n*3+0))++" " ++(show $ vec1 V.! (n*3+1)) ++ " " ++(show $ vec1 V.! (n*3+2)) ++ "\n"
                        my_recur  vec1 h1 sum1 (n+1)   
        list_remove::Int-> Int
        list_remove _ = 3

                    ---VM.write  vec1 (n*3+0) $ runGet getFloatle s
    ----putStrLn $ show $ list_remove 4
    h1<- openBinaryFile "tree.pcd" ReadMode
    h2<- openFile "tree1.pcd" WriteMode
    s<- pcd_get_header h1

    (sum,tsum)<-return $ pcd_get_header_info s 
    hPutStr h2 $ pcd_alter_header s


    vec<-VM.new (tsum*3)
    pcd_fill_vector h1 (sum,tsum) vec
    vec1<-  V.freeze vec
    
    pcd_write_file vec1 h2 tsum


    -- s<-BL.hGet h1 4
    ---putStrLn $show $runGet getFloatle s 
    -- putStrLn$ BLC.unpack s
    -- putStrLn $ show  $ str_get_words_index "fds ojibd\n dsoppqm\nlpps d" "dsoppqm"
    hClose h1
    hClose h2
    putStrLn "end"
    return () 

--list_remove::
main :: IO ()
main = test
